/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package drt;

import evaluation.Edge;
import evaluation.Graph;
import evaluation.Vertex;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import logic.Type;
import util.Util;

/**
 *
 * @author phong
 */
public class DRSPredCondition extends DRSBasicCondition {
    
    String symbol;
    List<DrtEntity> args;
    
    protected DRSPredCondition() {
        
    }
    
    public DRSPredCondition(String symbol, DrtEntity arg) {
        this.symbol = symbol;
        this.args = new LinkedList<DrtEntity>();
        this.args.add(arg);
    }
    
    public DRSPredCondition(String symbol, DrtEntity arg1, DrtEntity arg2) {
        this.symbol = symbol;
        this.args = new LinkedList<DrtEntity>();
        this.args.add(arg1);
        this.args.add(arg2);
    }

    public DRSPredCondition(String symbol, List<DrtEntity> args) {
        this.symbol = symbol;
        this.args = args;
    }
    
    public String getSymbol() {
        return this.symbol; 
    }
    
    public List<DrtEntity> getArgs() {
        return this.args;
    }
    
    @Override
    public Type getType() {
        return Type.TRUTH_TYPE;
    }
    
    @Override
    public void setType(Type t) {}
    
    @Override
    public void getAllVariables(LinkedHashSet<DrtVariable> vars) {
        for (DrtEntity arg : this.args) {
            arg.getAllVariables(vars);
        }
    }

    @Override
    public void getRefs(LinkedHashSet<DRSReferent> refs) {
        for (DrtEntity arg : this.args) {
            arg.getRefs(refs);
        }
    }
    
    @Override
    public DRSPredCondition simplify() {
        return this;
    }
    
    @Override
    public DRSPredCondition replace(DrtVariable var, DrtExpression exp) {
        List<DrtEntity> newArgs = new LinkedList<DrtEntity>();
        for (DrtEntity arg : this.args) {
            if (arg.equals(var)) {
                if (exp instanceof DrtEntity)
                    newArgs.add((DrtEntity)exp);
                else if (exp instanceof DrtVariable ){
                    DrtEntityVariable v = new DrtEntityVariable(((DrtVariable)exp).getName());
                    newArgs.add(v);
                }
                else 
                    throw new Error("incorrect type");
            }
            else 
                newArgs.add(arg);
        }
        return new DRSPredCondition(symbol, newArgs);
    }
    
    @Override
    public boolean equals(Object other) {
        if (other instanceof DRSPredCondition) {
            DRSPredCondition that = (DRSPredCondition)other;
            return that.symbol.equals(this.symbol) && that.args.equals(this.args);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        int hc = this.symbol.hashCode();
        return hc;
    }
    
    @Override
    public String toString() {
        return this.symbol + "(" + Util.joinToString(args, ",") + ")";
    }
    
    @Override
    public Graph toGraph() {
        Graph g = new Graph();
        
        // unary predicate
        if (this.args.size() == 1) {
            Vertex v = new Vertex(this.args.get(0).getName(), Vertex.TYPE_REF);
            Vertex f = new Vertex(this.symbol, Vertex.TYPE_PRED);
            g.addEdge(new Edge("", v, f));
            g.addMarks(f);
        }
        
        // binary predicate
        else if (this.args.size() == 2) {
            Vertex v1 = new Vertex(this.args.get(0).getName(), Vertex.TYPE_REF);
            Vertex v2 = new Vertex(this.args.get(1).getName(), Vertex.TYPE_REF);
            Vertex f = new Vertex(this.symbol, Vertex.TYPE_PRED);
            g.addEdge(new Edge("1", v1, f));            
            g.addEdge(new Edge("2", v2, f));            
            g.addMarks(f);
        }
        
        else 
            throw new Error("not handle n-ary predicate with n > 2");
        
        return g;
    }
    
    @Override
    public DRSPredCondition getTemplate(Map<String,String> map) {
        // don't templatize binary predicates
        if (this.args.size() == 2)
            return this;
        
        else {
            String template = map.get(this.symbol);
            if (template == null) {
                template = TemplateNaming.getUniqueName();
                map.put(symbol, template);
            }
            return new DRSPredCondition(template, args);
        }
            
    }
}
